// hwinfiledialog.h

#pragma once
#ifndef __HWINFILEDIALOG_H__
#define __HWINFILEDIALOG_H__

#include "hwindef.h"
#include "hwincom.h"
#include "hwinexception.h"
#include "hwinvariant.h"
#include "hwinobj.h"
#include "hwinshell.h"


namespace harlinn
{
    namespace windows
    {
        class Control;
        class ModalWindow : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(ModalWindow,Unknown,IModalWindow,IUnknown)

            HWIN_EXPORT virtual bool Show(HWND theOwner);
            HWIN_EXPORT bool Show( const std::shared_ptr<Control>& theOwner );
            
        };


        class FileDialogEvents : public Unknown
        {
        public:
            typedef Unknown Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(FileDialogEvents,Unknown,IFileDialogEvents,IUnknown)

            HWIN_EXPORT FileDialogEvents& OnFileOk(IFileDialog *pfd)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->OnFileOk(pfd);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

        
            HWIN_EXPORT FileDialogEvents& OnFolderChanging(IFileDialog *pfd,IShellItem *psiFolder)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->OnFolderChanging(pfd,psiFolder);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            HWIN_EXPORT FileDialogEvents& OnFolderChange(IFileDialog *pfd)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->OnFolderChange(pfd);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            HWIN_EXPORT FileDialogEvents& OnSelectionChange(IFileDialog *pfd)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->OnSelectionChange(pfd);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            HWIN_EXPORT FileDialogEvents& OnShareViolation(IFileDialog *pfd,IShellItem *psi,FDE_SHAREVIOLATION_RESPONSE *pResponse)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->OnShareViolation(pfd,psi,pResponse);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            HWIN_EXPORT FileDialogEvents& OnTypeChange(IFileDialog *pfd)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->OnTypeChange(pfd);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

            HWIN_EXPORT FileDialogEvents& OnOverwrite(IFileDialog *pfd,IShellItem *psi,FDE_OVERWRITE_RESPONSE *pResponse)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->OnOverwrite(pfd,psi,pResponse);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
            
        };


        


        class FileDialog;
        class FileDialogEventsImplementation : public IUnknownImplementation<IFileDialogEvents>
        {
            FileDialog* fileDialog;
        public:
            typedef IUnknownImplementation<IFileDialogEvents> Base;

            HWIN_EXPORT FileDialogEventsImplementation(FileDialog* theFileDialog);

            HWIN_EXPORT virtual HRESULT STDMETHODCALLTYPE OnFileOk(IFileDialog *pfd);
        
            HWIN_EXPORT virtual HRESULT STDMETHODCALLTYPE OnFolderChanging(IFileDialog *pfd,IShellItem *psiFolder);
        
            HWIN_EXPORT virtual HRESULT STDMETHODCALLTYPE OnFolderChange(IFileDialog *pfd);
        
            HWIN_EXPORT virtual HRESULT STDMETHODCALLTYPE OnSelectionChange(IFileDialog *pfd);
        
            HWIN_EXPORT virtual HRESULT STDMETHODCALLTYPE OnShareViolation(IFileDialog *pfd,IShellItem *psi,FDE_SHAREVIOLATION_RESPONSE *pResponse);
        
            HWIN_EXPORT virtual HRESULT STDMETHODCALLTYPE OnTypeChange(IFileDialog *pfd);
        
            HWIN_EXPORT virtual HRESULT STDMETHODCALLTYPE OnOverwrite(IFileDialog *pfd,IShellItem *psi,FDE_OVERWRITE_RESPONSE *pResponse);
        };

        class FileDialog : public ModalWindow
        {
            friend class FileDialogEventsImplementation;
        public:
            typedef ModalWindow Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(FileDialog,ModalWindow,IFileDialog,IModalWindow)

            HWIN_EXPORT virtual bool Show(HWND theOwner);


            FileDialog& SetFileTypes( UINT cFileTypes, const COMDLG_FILTERSPEC *rgFilterSpec)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetFileTypes( cFileTypes, rgFilterSpec );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FileDialog& SetFileTypeIndex( UINT iFileType )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetFileTypeIndex( iFileType );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            UINT GetFileTypeIndex( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                UINT result = 0;
                auto hr = pInterface->GetFileTypeIndex( &result );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            DWORD Advise( IFileDialogEvents *pfde )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                DWORD result = 0;
                auto hr = pInterface->Advise( pfde, &result );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            FileDialog& Unadvise( DWORD dwCookie )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->Unadvise( dwCookie );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FileDialog& SetOptions( FILEOPENDIALOGOPTIONS fos)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetOptions( fos );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FILEOPENDIALOGOPTIONS GetOptions( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                FILEOPENDIALOGOPTIONS result = 0;
                auto hr = pInterface->GetOptions( &result );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return result;
            }
        
            FileDialog& SetDefaultFolder( IShellItem *psi)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetDefaultFolder( psi );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FileDialog& SetFolder( IShellItem *psi)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetFolder( psi );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            ShellItem GetFolder( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IShellItem* pShellItem = nullptr;
                auto hr = pInterface->GetFolder( &pShellItem );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                IShellItem2* result = nullptr;
                hr = pShellItem->QueryInterface(&result);
                pShellItem->Release();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return ShellItem(result);
            }
        
            ShellItem GetCurrentSelection( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IShellItem* pShellItem = nullptr;
                auto hr = pInterface->GetCurrentSelection( &pShellItem );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                IShellItem2* result = nullptr;
                hr = pShellItem->QueryInterface(&result);
                pShellItem->Release();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return ShellItem(result);
            }
        
            FileDialog& SetFileName( LPCWSTR pszName )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetFileName(pszName);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }


            String GetFileName( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                LPWSTR result;
                auto hr = pInterface->GetFileName(&result);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                String s(result);
                CoTaskMemFree(result);
                return s;
            }
            FileDialog& SetTitle( LPCWSTR pszTitle)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetTitle(pszTitle);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FileDialog& SetOkButtonLabel( LPCWSTR pszText)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetOkButtonLabel(pszText);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FileDialog& SetFileNameLabel( LPCWSTR pszLabel )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetFileNameLabel(pszLabel);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            ShellItem GetResult( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IShellItem* pShellItem = nullptr;
                auto hr = pInterface->GetResult( &pShellItem );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                IShellItem2* result = nullptr;
                hr = pShellItem->QueryInterface(&result);
                pShellItem->Release();
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return ShellItem(result);
            }
        
            FileDialog& AddPlace( IShellItem *psi,FDAP fdap = FDAP_BOTTOM)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->AddPlace(psi,fdap);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FileDialog& SetDefaultExtension( LPCWSTR pszDefaultExtension)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetDefaultExtension(pszDefaultExtension);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FileDialog& Close( HRESULT hr )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hres = pInterface->Close( hr );
                if(FAILED(hres))
                {
                    CheckHRESULT(hres);
                }
                return *this;
            }
        
            FileDialog& SetClientGuid( REFGUID guid )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetClientGuid( guid );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FileDialog& ClearClientData( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->ClearClientData( );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FileDialog& SetFilter( IShellItemFilter *pFilter)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetFilter( pFilter );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }


            boost::signals2::signal<void (FileDialog* sender, bool& accept ) > OnFileOk;
        
            boost::signals2::signal<void (FileDialog* sender, const ShellItem& newFolder, bool& allow) > OnFolderChanging;
        
            boost::signals2::signal<void (FileDialog* sender) > OnFolderChange;
        
            boost::signals2::signal<void ( FileDialog* sender ) > OnSelectionChange;
        
            boost::signals2::signal<void (FileDialog* sender, const ShellItem& shellItem, FDE_SHAREVIOLATION_RESPONSE& response) > OnShareViolation;
        
            boost::signals2::signal<void ( FileDialog* sender ) > OnTypeChange;
        
            boost::signals2::signal<void (FileDialog* sender, const ShellItem& shellItem, FDE_OVERWRITE_RESPONSE& response) > OnOverwrite;

        protected:
            HWIN_EXPORT virtual void DoOnFileOk( bool& accept );
        
            HWIN_EXPORT virtual void DoOnFolderChanging(const ShellItem& newFolder, bool& allow);
        
            HWIN_EXPORT virtual void DoOnFolderChange();
        
            HWIN_EXPORT virtual void DoOnSelectionChange( );
        
            HWIN_EXPORT virtual void DoOnShareViolation(const ShellItem& shellItem, FDE_SHAREVIOLATION_RESPONSE& response);
        
            HWIN_EXPORT virtual void DoOnTypeChange();
        
            HWIN_EXPORT virtual void DoOnOverwrite(const ShellItem& shellItem, FDE_OVERWRITE_RESPONSE& response);

        };


        class FileOpenDialog : public FileDialog
        {
        public:
            typedef FileDialog Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(FileOpenDialog,FileDialog,IFileOpenDialog,IFileDialog)

            HWIN_EXPORT static std::shared_ptr<FileOpenDialog> Create();

            ShellItemArray GetResults( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IShellItemArray* pResult = nullptr;
                auto hr = pInterface->GetResults(&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return ShellItemArray(pResult);
            }
        
            ShellItemArray GetSelectedItems( )
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IShellItemArray* pResult = nullptr;
                auto hr = pInterface->GetSelectedItems(&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return ShellItemArray(pResult);
            }


        };


        class FileSaveDialog : public FileDialog
        {
        public:
            typedef FileDialog Base;
            HARLINN_WINDOWS_COM_STANDARD_METHODS_IMPL(FileSaveDialog,FileDialog,IFileSaveDialog,IFileDialog)

            HWIN_EXPORT static std::shared_ptr<FileSaveDialog> Create();

            FileSaveDialog& SetSaveAsItem( IShellItem *psi)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetSaveAsItem( psi);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FileSaveDialog& SetProperties( IPropertyStore *pStore)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetProperties( pStore );
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            FileSaveDialog& SetCollectedProperties( IPropertyDescriptionList *pList, bool appendDefault)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->SetCollectedProperties( pList, appendDefault);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }
        
            PropertyStore GetProperties()
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                IPropertyStore* pResult = nullptr;
                auto hr = pInterface->GetProperties(&pResult);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return PropertyStore(pResult);
            }
        
            FileSaveDialog& ApplyProperties( IShellItem *psi, IPropertyStore *pStore, HWND hwnd, IFileOperationProgressSink *pSink)
            {
                HWIN_TRACE();
                auto pInterface = GetInterface();
                auto hr = pInterface->ApplyProperties( psi, pStore, hwnd, pSink);
                if(FAILED(hr))
                {
                    CheckHRESULT(hr);
                }
                return *this;
            }

        };


    };
};


#endif //__HWINFILEDIALOG_H__